﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DiscreteMath
{
    /// <summary>
    /// Defines common extension methods.
    /// </summary>
	public static class Extensions
	{
        /// <summary>
        /// Produces the union of this enumerable with the specified set of items.
        /// </summary>
        /// <typeparam name="T">The type of the elements in the collection.</typeparam>
        /// <param name="enumerable">The first argument of the union.</param>
        /// <param name="items">A set of elements representing the second part of the union.</param>
        /// <returns>A collection that contains all elements that are either in items or in enumerable</returns>
        public static IEnumerable<T> Union<T>(this IEnumerable<T> enumerable, params T[] items)
        {
            return enumerable.Union(items, EqualityComparer<T>.Default);
        }

        /// <summary>
        /// Returns a value indicating whether this string contains any of the specified states.
        /// </summary>
        /// <param name="value">The string to test in.</param>
        /// <param name="enumerable">A collection of states to test for.</param>
        /// <returns>True if the name of any state in collection is present in the string, false otherwise.</returns>
        public static bool ContainsAny(this string value, IEnumerable<State> enumerable)
        {
            foreach (var item in enumerable)
            {
                if (value.Contains(item))
                    return true;
            }
            return false;
        }

        /// <summary>
        /// Converts the specified collection to <see cref="TransitionDictionary"/>
        /// </summary>
        /// <param name="enumerable">A collection to convert to <see cref="TransitionDictionary"/>.</param>
        /// <returns>An instance of <see cref="TransitionDictionary"/> equivalent to the specified collection.</returns>
		public static TransitionDictionary ToTransitionDictionary(
            this IEnumerable<KeyValuePair<Configuration, ISet<State>>> enumerable)
		{
			var dict = enumerable.ToDictionary(x => x.Key, x => new HashSet<State>(x.Value) as ISet<State>);
			return new TransitionDictionary(dict);
		}

        /// <summary>
        /// Prints the specified collection in a human readable way.
        /// </summary>
        /// <typeparam name="T">The type of the elements in the collection.</typeparam>
        /// <param name="enumerable">The collection to print.</param>
        /// <returns>Text representing the collection in a human-friendly way.</returns>
		public static string Print<T>(this IEnumerable<T> enumerable)
		{
            return Print(enumerable, ",");
		}

        public static string Print<T>(this IEnumerable<T> enumerable, string delimiter)
        {
            StringBuilder builder = new StringBuilder();
            builder.Append("{");
            foreach (var item in enumerable)
            {
                builder.Append(item + delimiter + " ");
            }
			// Remove the last interval and delimiter
			builder.Remove(builder.Length - 2, 2);
            builder.Append("}");
            return builder.ToString().Replace(delimiter + " }", " }");
        }

        /// <summary>
        /// Prints the specified collection in a human readable way but first transforms all of its elements by the given functions.
        /// </summary>
        /// <typeparam name="T">The type of the elements in the collection.</typeparam>
        /// <param name="enumerable">The collection to print.</param>
        /// <returns>Text representing the collection in a human-friendly way.</returns>
        public static string Print<T, K>(this IEnumerable<T> enumerable, Func<T, K> transformation)
        {
            return Print(enumerable, transformation, true);
        }

        /// <summary>
        /// Prints the specified collection in a human readable way but firsts transforms all of its elements by the given functions.
        /// </summary>
        /// <typeparam name="T">The type of the elements in the collection.</typeparam>
        /// <param name="enumerable">The collection to print.</param>
        /// <param name="shouldAddBrackets">If false no opening/closing brackets will be added.</param>
        /// <returns>Text representing the collection in a human-friendly way.</returns>
        public static string Print<T, K>(this IEnumerable<T> enumerable, Func<T, K> transformation, bool shouldAddBrackets)
        {
            StringBuilder builder = new StringBuilder();
            if (shouldAddBrackets)
                builder.Append("{ ");
            foreach (var item in enumerable)
            {
                builder.Append(transformation(item) + ", ");
            }
            if (shouldAddBrackets)
                builder.Append("}");

            return builder.ToString().Replace(", }", " }");
        }

        /// <summary>
        /// Produces a hash code for the tuple consisting of this object and all args.
        /// </summary>
        /// <param name="obj">The object to hash.</param>
        /// <param name="args">Additional arguments to be hashed with the object..</param>
        /// <returns>Hash code usable by dictionaries, hashtables, etc.</returns>
		public static int HashWith(this object obj, params object[] args)
		{
			// Use the algorithm given in Josh Bloch's fabulous Effective Java
			unchecked
			{
				int hash = 17 * 23 + obj.GetHashCode();

				foreach (var argument in args)
				{
					hash = hash * 23 + argument.GetHashCode();
				}

				return hash;
			}
		}

        public static ISet<T> ToSet<T>(this IEnumerable<T> enumerable)
        {
            return new HashSet<T>(enumerable);
        }
	}
}
